pub fn scope() {
    let x = "hello"; // &str 类型是定长的，可以被硬编码的，所以是存在栈上
    let y = x; // 栈上的数据被赋值，会独立的开辟一块栈空间，这里不会涉及到深拷贝和浅拷贝概念
    println!("x:{}, y: {}", x, y);

    let x = 5;
    let mut y = x;
    y += 1; // y的改变并不会影响到x
    println!("x:{}, y: {}", x, y);

    // let x = String::from("hello"); // String是不定长数据，存在堆上
    // let y = x; // 这里的等于号(=)不再是赋值操作，而是移动操作，将指向堆上的指针移动到了y，随即x失效
    // println!("x:{}, y: {}", x, y); // 会报错，因为，这里x的指针已经移动到了y，且x被废弃了（避免了歧义，很好的设计）

    let x = String::from("hello");
    let y = x.clone(); // 深拷贝，此时x所指向的堆上的数据被拷贝了一份，y的指针指向这份被拷贝的数据
    println!("x:{}, y: {}", x, y); // 由于是深拷贝，原来的x也被保留了，所以不会报错

    let name = String::from("cargo");
    // 此时值已经被移动了，相应的作用域也被转交到了函数中；同时函数的返回值将所有权移交给了hello_name
    let hello_name = scope_and_owner_a(name);
    // println!("Hello, {}!",  name);  // 到这里的时候函数掉完成，name就已经被注销了，所以从这里以后就不可以再调用name了
    println!("{}", hello_name);

    let name = "cargo";
    // 此时的name是字面量，是硬编码，存在栈中，不会被移动；同时函数的返回值将所有权移交给了hello_name
    let hello_name = scope_and_owner_b(name);
    println!("Hello, {}!", name); // 此时再次调用name是可以的，因为没有被移动也就不会被注销
    println!("{}", hello_name);

    // 场景：我有一个数据，我想在后续保留它，但是我又不得不调用一个函数来得到更多信息；比如：临时计算一下一个字符串长度
    // 1. 使用元组解构函数返回值(很啰嗦，很麻烦，每次都要记得把原来的数据再移交回来)
    let s1 = String::from("hello");
    let (s1, len) = calculate_length(s1);
    println!("The length of '{}' is {}.", s1, len);
    // 2. 引用
    let s1 = String::from("hello");
    let len = calculate_length_b(&s1); // 把s1的指针的指针传入，就不会移交所有权，同时函数也可以访问到这片值
    println!("The length of '{}' is {}.", s1, len);

    // 拓展：在另一个作用域中修改数据
    let mut s1 = String::from("hello"); //首先声明的变量要可变
    change_s1(&mut s1); // 传入可变的引入
    println!("Change the s1 to '{}'", s1); // 值被修改了
    change_s2(&mut s1);
    println!("Change the s1 to '{}'", s1); // 值被修改了

    // 不可变引用即为读引用，可变引用即为写引用
    let mut s1 = String::from("hello");
    let r1 = &s1; // 同时可以存在多个读引用
    let r2 = &s1; // 同时可以存在多个读引用
    // let w = &mut s1; // 当其他引用（不论读写）存在时，创建写引用将会有风险
    println!("{}", r1); // 此时一个读引用被调用，rust无法保证r2的数据内存读取是安全的，所以上一行报错了
    println!("{}", r2); // 此时一个读引用被调用，rust无法保证r2的数据内存读取是安全的，所以上一行报错了

    //  slice
    let mut s = String::from("hello world");
    let word = first_word(&s); // `s`已经被借出（通过不可变引用）
    // s.clear(); // 在引用被归还之前（后面word还被用，此时借出就无法被归还）不能再以可变引用被借出 (避免悬垂引用，保证内存安全)
    // s = String::from("hello rust "); // 在引用被归还之前（后面word还被用，此时借出就无法被归还）不能被修改（避免悬垂引用，保证内存安全）
    println!("the first word is: {}", word); // 此处调用了word，说明此前借用的`s`一直没有被归还
}

fn first_word(s: &String) -> &str {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }

    &s[..]
}

fn change_s1(some_string: &mut String) {
    some_string.push_str(", world");
}

fn change_s2(some_string: &mut String) {
    *some_string = String::from("abc") // 复制操作要取得下面一层的指针，以便将地址重新指向新的堆中的值
}

fn scope_and_owner_a(name: String) -> String {
    format!("Hello, {}!", name)
}

fn scope_and_owner_b(name: &str) -> String {
    format!("Hello, {}!", name)
}

fn calculate_length(s: String) -> (String, usize) {
    let length = s.len(); // len() 返回字符串的长度
    (s, length) // 使用元组打包返回值
}

fn calculate_length_b(s: &String) -> usize {
    s.len()
}
